package com.tgjorgoski.sidekicknotes.htmlview;

import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.*;
import java.util.*;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.*;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.StyleSheet;

import com.tgjorgoski.sidekicknotes.filedata.FileInformation;
import com.tgjorgoski.sidekicknotes.rtfview.support.*;
import com.tgjorgoski.utils.*;
import com.tgjorgoski.window.HTMLView;
import com.tgjorgoski.window.Session;

public class HTMLEditor extends JTextPane implements DocumentListener, PropertyChangeListener {
	HTMLEditorKit htmlEditorKit;
	String lastSelected;
	Style defaultStyle;
	AttributeSet defaultAttributes;
	File openedFile;
	HTMLView htmlView;
	
	Paint imagePaint;
	Color c1 = new Color(170,170,255);
	Color c2 = c1.darker().darker();
	
	public void paintComponent (Graphics g)
    {
		Graphics2D g2d = (Graphics2D)g;
		Paint oldPaint = g2d.getPaint();
		
		if (imagePaint!=null) {
			g2d.setPaint(imagePaint);
	        g2d.fillRect(0, 0, getWidth(), getHeight());
	        g2d.setPaint(oldPaint);
		} else {
			g2d.setColor(Color.WHITE);
			g2d.fillRect(0,0,getWidth(),getHeight());
		}
		
		//Paint gradPaint = new GradientPaint(0, 0, c1, getWidth(), 0, Color.WHITE);
		//g2d.setPaint(gradPaint);
		g2d.setColor(c1);
		g2d.fillRect(0, 0, getWidth(), 3);
		g2d.fillRect(0, 0, 3, getHeight());
		g2d.fillRect(0, getHeight()-3, getWidth(), getHeight());


		g2d.setColor(Color.BLACK);
		g2d.drawLine(3, 3, getWidth(), 3);
		g2d.drawLine(3, getHeight()-3, getWidth(), getHeight()-3);
		g2d.drawLine(3, 3, 3, getHeight()-3);

		g2d.setColor(c2);
		g2d.drawLine(7, getHeight()-2, getWidth(), getHeight()-2);
		
        super.paintComponent(g);
    }
	
	public void setImage(ImageIcon image) {
		if (image==null) {
			setOpaque(true);
		} else {
			setOpaque(false);
			BufferedImage bi = IconResource.getCompatibleImage(image);
			int w = bi.getWidth(); int h=bi.getHeight();
			imagePaint=new TexturePaint(IconResource.getCompatibleImage(image), new Rectangle(w,h));
		}
	}
	
	public HTMLEditor(HTMLView view) {
		this.htmlView=view;
		setBackground(Color.white);
		setOpaque(false);
		//setImage(IconResource.getIconResource("retro.jpg"));
		
		htmlEditorKit = new HTMLEditorKitChanged();
		htmlEditorKit.setDefaultCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
		StyleSheet css = htmlEditorKit.getStyleSheet();
        String styleChanges = 
            "p { margin-top: 0; margin-bottom: 0; margin-left: 0; margin-right: 0 }" +
            "body { font-size:12pt; font-family:Tahoma; margin-top: 0; margin-bottom: 0; margin-left: 0; margin-right: 0 }" +
            "html { margin-top: 5; margin-bottom: 5; margin-left:5;}";
        css.addRule(styleChanges);

		setEditorKit(htmlEditorKit);
		
		SpellCheckSupport.getInstance().registerComponent(this);
		UndoRedoSupport.getInstance().registerComponent(this);
		EvaluateSupport.getInstance().registerComponent(this);
		IndentSupport.getInstance().registerComponent(this);
		SubSuperStrikeSupport.getInstance().registerComponent(this);
		
		
		KeyBindings.setKeyBindings(this);
		//setTabs();
		
		defaultAttributes=getCharacterAttributes();
		
		createActionTable(this);
		getDocument().addDocumentListener(this);
		
		//on change of the page, we reset the modified flag
		//and re-attach the document listeners
		addPropertyChangeListener("page", this);
		Session.addPropertyChangeListener(this);
		
		KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener("focusOwner", this);
	}
	
	
	private FileInformation openedFileInformation=null;
	private void updateOpenedFileInformation() {
		if (openedFile!=null) {
			openedFileInformation = FileInformation.getFileInformation(openedFile);
		} else {
			openedFileInformation=null;
		}
	}
	private FileInformation getOpenedFileInformation() {
		return openedFileInformation;
	}
	public boolean shouldSpellcheck() {
		boolean shouldSpellcheck = Session.isSpellcheckByDefaultOn();;
		if (openedFileInformation!=null) {
			if (openedFileInformation.getUseSpellCheck()==FileInformation.SPELLCHECK_USE) {
				shouldSpellcheck=true;
			} else if (openedFileInformation.getUseSpellCheck()==FileInformation.SPELLCHECK_DONT_USE) {
				shouldSpellcheck=false;
			}
		}
		return shouldSpellcheck;
	}
	
	
	public void paste() {
		if (isEditable() && isEnabled()) {
			TransferHandler th = getTransferHandler();
			Clipboard clipboard = ClipboardUtil.getDefaultClipboard();
			Transferable tr = clipboard.getContents(this);
			boolean stringPresent = tr.isDataFlavorSupported(DataFlavor.stringFlavor);
            // this is a paste action, import data into the component
            if (tr != null) {
                th.importData(this, tr);
            }

 		}
	}
	
	public void clearFormatting() {
		setCharacterAttributes(defaultAttributes, true);
	}
	
    HashMap actions;
    //The following two methods allow us to find an
    //action provided by the editor kit by its name.
    private void createActionTable(JTextComponent textComponent) {
        actions = new HashMap();
        Action[] actionsArray = textComponent.getActions();
        for (int i = 0; i < actionsArray.length; i++) {
            Action a = actionsArray[i];
            actions.put(a.getValue(Action.NAME), a);
        }
    }
    public Action getActionByName(String name) {
        return (Action)(actions.get(name));
    }
    
	public void load(File file) {
		// Load a HTML file into the editor
		try {
			getDocument().removeDocumentListener(this);
			setPage(file.toURL());
			openedFile=file;
			updateOpenedFileInformation();
			//we don't reset modified here, instead we are listening for change to the document
			
			//update "last opened"
			FileInformation fi = FileInformation.getFileInformation(file);
			fi.setLastOpened(new Date());
			Session.getPersistManager().saveObject(fi);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public void newDocument() {
		openedFile=null;
		updateOpenedFileInformation();
		getDocument().removeDocumentListener(this);
		Document doc = htmlEditorKit.createDefaultDocument();
		setDocument(doc);
		UndoRedoSupport.getInstance().switchToNewDocument(doc);
		SpellCheckSupport.getInstance().switchToNewDocument(doc);
		getDocument().addDocumentListener(this);
		resetModified();
		requestFocusInWindow();
	}
	
	private void setTabs() {
		//Create one of each type of tab stop
	    java.util.List<TabStop> list = new ArrayList<TabStop>();
	    
	    // Create a left-aligned tab stop at 100 pixels from the left margin
	    for (float pos=40; pos<500; pos+=40) {
		    int align = TabStop.ALIGN_LEFT;
		    int leader = TabStop.LEAD_NONE;
		    TabStop tstop = new TabStop(pos, align, leader);
		    list.add(tstop);
	    }
	    
	    // Create a tab set from the tab stops
	    TabStop[] tstops = (TabStop[])list.toArray(new TabStop[0]);
	    TabSet tabs = new TabSet(tstops);
	    
	    // Add the tab set to the logical style;
	    // the logical style is inherited by all paragraphs
	    Style style = getLogicalStyle();
	    StyleConstants.setTabSet(style, tabs);
	    setLogicalStyle(style);		
	}

	public File getOpenedFile() {
		return openedFile;
	}
	public void setOpenedFile(File openedFile) {
		this.openedFile=openedFile;
		updateOpenedFileInformation();
		
		FileInformation fi = getOpenedFileInformation();
		fi.setLastOpened(new Date());
		Session.getPersistManager().saveObject(fi);
	}

	private boolean modified=false;
	public void changedUpdate(DocumentEvent arg0) {
		setModified();
	}

	public void insertUpdate(DocumentEvent arg0) {
		setModified();
	}

	public void removeUpdate(DocumentEvent arg0) {
		setModified();
	}
	private void setModified() {
		if (!modified) {
			modified=true;
			htmlView.updateTitle();
		}
	}
	public boolean isModified() {
		return modified;
	}
	public void resetModified() {
		if (modified) {
			modified=false;
			htmlView.updateTitle();
		}
	}
	
	public void updateSpellcheckState() {
		if (!shouldSpellcheck()) {
			SpellCheckSupport.getInstance().removeHighlights();
		} else {
			SpellCheckSupport.getInstance().updateHighlights();
		}
	}

	public void propertyChange(PropertyChangeEvent evt) {
		if (evt.getPropertyName().equals("page")) {
			getDocument().addDocumentListener(this);
			resetModified();
			boolean fail = requestFocusInWindow();
			//set the caret at the end
			//setCaretPosition(getDocument().getLength());
		} else if (evt.getPropertyName().equals(Session.PREF_SPELLCHECK)) {
			updateSpellcheckState();
		}
	}
}
